<!-- 
  通达信链接：
  http://www.treeid/dlglocalurl##homepath##company/kpl涨停原因.html?stock_code=xxxxxx&stock_name=##STOCKNAME##

  使用说明：
  1. 此页面用于查询指定股票的涨停原因信息
  2. 通过在URL参数中传递stock_code来指定要查询的股票代码
  3. html须放置在通达信根目录下的company、jmpages等目录下，不能放置在通达信根目录
  4. 由于需要解决跨域问题，页面通过代理服务器(10.0.0.6:9999)请求数据，如果需要更换代理地址，请修改 proxyUrl 变量的配置
  5. 页面包含自动刷新功能，当通达信软件股票代码变更时会自动更新数据
  
  技术说明：
  - 使用fetch API通过代理服务器(10.0.0.6:9999)请求数据
  - 数据源：https://apphis.longhuvip.com/w1/api/
  - 页面包含自动刷新功能，当股票代码变更时会自动更新数据
-->
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>涨停原因</title>
    <style>
      html, body {
        font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
        font-size: 13px; /* 设置默认字体大小为12px */
        max-width: 1200px;
        margin: 0 auto !important; /* 强制水平居中，取消所有默认margin */
        padding: 0 !important; /* 强制取消所有padding（包括顶部） */
        background-color: #000000; /* 整体背景设为黑色 */
        color: #d0d0d0; /* 全局默认文字白色，提升可读性 */
      }
      /* 容器样式 */
      .container {
        margin: 0 auto !important; /* 水平居中，顶部margin强制为0 */
        padding: 0 10px; /* 减小顶部内边距 */
        background-color: #060606; /* 容器背景深黑，与整体黑色区分 */
        border-radius: 10px;
        box-shadow: 0 2px 10px rgba(255, 255, 255, 0.1); /* 白色阴影适配黑色背景 */
      }
      /* 选中文本样式 */
      ::selection {
        background-color: #0775db; /* 选中文本的背景色 */
        color: #dfdfdf; /* 选中文本的颜色 */
      }
      .loading {
        text-align: center;
        color: #aaaaaa; /* 浅灰色加载文字，适配黑色背景 */
        margin: 20px 0;
      }
      .result {
        margin-top: 2px; /* 减小与顶部的间距 */
        padding: 15px;
        border-radius: 6px;
        border: 1px solid #333333; /* 深色边框适配黑色主题 */
        display: none;
      }
      .error {
        color: #d93025;
        background-color: #2d1412; /* 深色错误背景，适配黑色主题 */
        padding: 15px;
        border-radius: 6px;
        display: none;
      }
      pre {
        white-space: pre-wrap;
        word-wrap: break-word;
        font-size: 14px;
        line-height: 1.5;
        color: #ffffff; /* 代码块文字白色 */
      }
      .status {
        padding: 8px 12px;
        border-radius: 4px;
        font-weight: bold;
        margin-right: 10px;
      }
      .status-success {
        background-color: #137333; /* 深绿色状态背景，适配黑色主题 */
        color: #ffffff;
      }
      .status-error {
        background-color: #d93025;
        color: #ffffff;
      }
      /* 顶部股票名称、股票代码，样式 */
      .data-topic {
        background: #060606;
        margin-top: 0px; /* 减小距离顶部的距离 */
        margin-left: 10px; /* 设置距离左侧的距离为10px */
      }
      /* 数据项，样式 */
      .data-item {
        background: #0d0d0d;
        padding: 15px;
        margin-bottom: 15px;
        border-radius: 6px;
        transition: background-color 0.3s ease; /* 添加过渡效果 */
      }
      /* 添加鼠标悬停效果 */
      .data-item:hover {
        background: #181818; /* 更浅的背景色 */
      }
      /* 数据项，标题样式 */
      .data-title {
        color: #4285f4;
        font-weight: 600;
        margin-right: 8px;
      }
      /* 数据项，题材概念标签 */
      .concept-tag {
        font-size: 14px;
        font-weight: bold;
        color: #e900f1;
      }
      /* 数据项，涨停原因内容样式 */
      .data-content {
        color: #d0d0d0;
      }
      .data-row {
        margin-bottom: 10px;
        line-height: 1.35;
      }
      /* 数据项，股票代码样式 */
      .stock-name-code {
        font-size: 15px;
        font-weight: bold;
        color: #e77b22; /* 紫色字体 */
      }
      /* 数据项，交易日期样式 */
      .stock-date {
        color: #777777; /* 灰色字体 */
      }
      /* 数据项，个股地位样式 */
      .stock-status {
        color: #777777; /* 灰色字体 */
      }
      /* 数据项，行业原因样式 */
      .industry-reason {
        color: #777777; /* 灰色字体 */
      }
      /* 底部，响应时间绿色显示 */
      #responseTime {
        color: #4caf50; /* 亮绿色，适配黑色背景 */
        font-weight: 600;
      }
      /* 滚动条样式 */
      ::-webkit-scrollbar {
        width: 8px; /* 垂直滚动条宽度 */
        height: 8px; /* 水平滚动条高度 */
      }
      /* 滚动条样式 */
      ::-webkit-scrollbar-track {
        background: transparent;
      }
      /* 滚动条样式 */
      ::-webkit-scrollbar-thumb {
        background-color: rgba(0, 0, 0, 0.85);
        border-radius: 4px;
        border: 2px solid transparent; /* 可增加一点间隙感 */
      }
      /* 滚动条样式 针对 Firefox */
      html {
        scrollbar-width: thin; /* auto / thin / none */
        scrollbar-color: rgba(0, 0, 0, 0.85) transparent;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="loading" id="loading">
        <p>正在加载数据，请稍候...</p>
      </div>

      <div class="error" id="errorMsg"></div>

      <div class="result" id="resultContainer">
        <!-- 股票代码显示区域（在涨停原因列表上方） -->
        <div class="data-topic">
          <span class="data-content stock-name-code" id="stockName"></span>
          <span style="margin: 0 8px;"></span>
          <span class="data-content stock-name-code" id="stockCode"></span>
        </div>
        <!-- 分割线 -->
        <hr style="border: 0; height: 1px; background: #272727; margin: 10px 0;">
        <!-- 涨停原因列表 -->
        <div id="formattedData"></div>
        <div style="margin-bottom: 10px">
          <span class="status status-success" id="status">请求成功</span>
          <span id="responseTime"></span>
          <!-- 已设置绿色 -->
        </div>
      </div>
    </div>
    <script>
      // 提取文件名和目录名作为全局常量
      const url = window.location.href;
      const pathParts = url.split('/'); // 获取URL路径的数组
      const fileName = pathParts[pathParts.length - 1].split('?')[0]; // 获取文件名，去除查询参数
      const lastDirectory = pathParts[pathParts.length - 2]; // 获取最后一层目录名

      // 从URL参数中获取股票代码
      const urlParams = new URLSearchParams(window.location.search);
      var stockCode = urlParams.get("stock_code");
      var stockName = urlParams.get("stock_name"); // 获取股票名称
      var lastStockCode = stockCode; // 记录上一次的股票代码
      // 创建新的参数数组，排除stock_code和stock_name
      const remainingParamsArray = [];
      for (const [key, value] of urlParams.entries()) {
        // 跳过stock_code和stock_name参数
        if (key !== 'stock_code' && key !== 'stock_name') {
          remainingParamsArray.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
        }
      }
      // 将剩余参数用&连接
      const remainingParams = remainingParamsArray.join('&');

      // 代理服务器地址配置
      const hostname = "10.0.0.6" || "localhost";
      const protocol = window.location.protocol === "file:"
                        ? "http:"
                        : window.location.protocol;
      const proxyBaseUrl = `${protocol}//${hostname}:9999`;
      // 固定代理地址：10.0.0.6:9999
      const proxyUrl = `${proxyBaseUrl}/proxy`;

      // 获取DOM元素（新增股票代码显示元素）
      const loading = document.getElementById("loading");
      const errorMsg = document.getElementById("errorMsg");
      const resultContainer = document.getElementById("resultContainer");
      const formattedData = document.getElementById("formattedData");
      const responseTime = document.getElementById("responseTime");
      const status = document.getElementById("status");
      const stockCodeEl = document.getElementById("stockCode"); // 股票代码显示元素
      const stockNameEl = document.getElementById("stockName"); // 股票名称显示元素

      // 处理Reason文本格式（移除第一个分号，替换为换行）
      function formatReasonText(text) {
        if (!text) return "";
        let formatted = text;
        // 查找第一个"；"（中文分号）或";"（英文分号）
        const semicolonIndex = formatted.search(/[；]/);
        if (semicolonIndex !== -1) {
          // 提取分号前的部分并应用concept-tag样式
          const beforeSemicolon = formatted.substring(0, semicolonIndex);
          const afterSemicolon = formatted.substring(semicolonIndex + 1);
          formatted = `<span class="concept-tag">${beforeSemicolon}</span><br>${afterSemicolon}`;
        }
        // 将连续多个换行（\r\n\r\n）替换为单个换行（\r\n）
        formatted = formatted.replace(/\r\n\r\n+/g, "<br>");
        // 转换为HTML可识别的换行标签
        return formatted.replace(/\r\n/g, "<br>");
      }

      // 监测股票代码变化
      async function CheckStockCode() {
        // 构建新的URL，保持目录结构不变
        var newUrl = 'http://www.treeid/dlglocalurl##homepath##' + lastDirectory + '/' + fileName + '?stock_code=xxxxxx&stock_name=##STOCKNAME##';
        if (remainingParams) {
          newUrl += '&' + remainingParams;
        }
        
        window.location.replace(newUrl); // 替换页面

        // 获取URL参数对象
        const params = new URLSearchParams(window.location.search);
        // 更新当前股票代码和名称
        stockCode = params.get('stock_code');
        stockName = params.get('stock_name');
        
        // 如果股票代码发生变化，重新获取数据
        if(stockCode !== lastStockCode) {
            lastStockCode = stockCode;
            await fetchData();
        }
      }

      // 请求数据函数
      async function fetchData() {
        const startTime = performance.now();
        // API地址，根据股票代码生成，动态生成
        apiUrl = `https://apphis.longhuvip.com/w1/api/index.php?a=GetDayZhangTing&st=10&apiv=w38&c=HisLimitResumption&PhoneOSNew=2&Index=0&StockID=${stockCode}`;

        try {
          // 通过代理服务器请求API
          const response = await fetch(proxyUrl, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify({
              url: apiUrl,
              method: "GET",
              headers: {
                "User-Agent": "lhb/5.21.5 (com.kaipanla.www; build:0; iOS 18.5.0) Alamofire/4.9.1",
                Host: "apphis.longhuvip.com",
              },
            }),
          });

          const endTime = performance.now();
          responseTime.textContent = `${(endTime - startTime).toFixed(2)}ms`;
          
          // console.log(`请求完成，耗时: ${(endTime - startTime).toFixed(2)}ms`);

          /*
          // 记录响应信息
          console.log(`--- 响应状态 ---`);
          console.log(`状态码: ${response.status}`);
          console.log(`状态文本: ${response.statusText}`);
          console.log(`--- 响应标头 ---`);
          response.headers.forEach((value, key) => {
            console.log(`${key}: ${value}`);
          });
          */

          // 检查响应是否成功
          if (!response.ok) {
            const errorDetails = await response.text();
            throw new Error(
              `HTTP 错误！状态码: ${response.status}\n详情: ${errorDetails}`
            );
          }

          // 读取并解析数据
          // console.log(`--- 原始响应体 (文本形式) ---`);
          const rawResponseText = await response.text();
          // console.log(rawResponseText);
          const data = JSON.parse(rawResponseText);
          const list = data.List || [];

          // 显示股票代码（StockID值）
          const stockId = data.StockID || stockCode; // 优先从API返回取，无则用URL参数
          const stockNm = data.StockName || stockName; // 获取股票名称，避免变量名冲突
          stockCodeEl.textContent = stockId;
          stockNameEl.textContent = stockNm; // 显示股票名称

          // 显示格式化结果
          loading.style.display = "none";
          resultContainer.style.display = "block";
          status.className = "status status-success";
          status.textContent = "请求成功";

          if (list.length === 0) {
            formattedData.innerHTML = '<div class="data-item"><span class="data-content">暂无涨停数据</span></div>';
            // console.log("未获取到涨停数据");
            return;
          }

          // 渲染每条数据
          let html = "";
          list.forEach((item) => {
            const date = item.Date || "";
            // 优化地位提取：分割后取第一个部分，兼容分号移除逻辑
            const rank = item.SCLT || "";
            const industryReason = item.Boom_ZS || "";
            const limitUpReason = item.Reason || "";

            // 调用格式化函数处理Reason文本
            const formattedReason = formatReasonText(limitUpReason);

            html += `
                <div class="data-item">
                    <div class="data-row">
                        <span class="data-title">涨停日期：</span>
                        <span class="data-content stock-date">${date}</span>
                        <span class="data-title" style="margin-left: 20px;">个股地位：</span>
                        <span class="data-content stock-status">${rank}</span>
                    </div>
                    <div class="data-row">
                        <span class="data-title">行业原因：</span>
                        <span class="data-content industry-reason">${industryReason}</span>
                    </div>
                    <div class="data-row">
                        <span class="data-title">涨停原因：</span>
                        <span class="data-content">${formattedReason}</span>
                    </div>
                </div>
                `;
          });
          formattedData.innerHTML = html;
          // console.log(`成功渲染 ${list.length} 条数据`);
        } catch (error) {
          const endTime = performance.now();
          responseTime.textContent = `请求失败时间: ${(endTime - startTime).toFixed(2)}ms`;

          // 显示错误信息时仍展示股票代码
          stockCodeEl.textContent = stockCode;
          stockNameEl.textContent = stockName; // 显示股票名称
          
          // console.log(`请求失败: ${error.message}`, true);

          loading.style.display = "none";
          errorMsg.style.display = "block";
          errorMsg.textContent = `请求失败: ${error.message}\n\n请查看浏览器开发者工具的控制台(Console)获取更多信息。`;
          // console.error(`--- Fetch 错误 --- ${error.message}`, true);

          // 显示错误堆栈
          resultContainer.style.display = "block";
          status.className = "status status-error";
          status.textContent = "请求失败";
          formattedData.innerHTML = `<pre class="data-content">${error.stack}</pre>`;
        }
      }
      
      // 页面加载完成后自动请求数据（移除按钮，直接执行）
      window.onload = function() {
        // console.log("页面加载完成，开始获取数据");
        fetchData();
      };

      // 使用更频繁的检查间隔，并添加多种检查方式
      setInterval(CheckStockCode, 1000);
    </script>
  </body>
</html>
